﻿namespace wToggle.Platform.Data
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;

    using wToggle.Platform.Interfaces;

    [DataContract]
    public sealed class OfflineCache
    {
        public OfflineCache()
        {
            this.SetDefaults();
        }

        [DataMember(Name = "tags")]
        public Dictionary<ulong, CacheRecord<Tag>> Tags { get; set; }

        [DataMember(Name = "clients")]
        public Dictionary<ulong, CacheRecord<Client>> Clients { get; set; }

        [DataMember(Name = "entries")]
        public Dictionary<ulong, CacheRecord<TimeEntry>> TimeEntries { get; set; }

        [DataMember(Name = "projs")]
        public Dictionary<ulong, CacheRecord<Project>> Projects { get; set; } 

        [DataMember(Name = "wspaces")]
        public Dictionary<ulong, CacheRecord<Workspace>> Workspaces { get; set; }

        [DataMember(Name = "user")]
        public CacheRecord<UserData> UserData { get; set; }

        [DataMember(Name = "tewrites")]
        public List<WriteRecord<TimeEntry>> TimeEntryWriteCache { get; set; }

        [DataMember(Name = "wwrites")]
        public List<WriteRecord<Workspace>> WorkspaceWriteCache { get; set; }

        [DataMember(Name = "cwrites")]
        public List<WriteRecord<Client>> ClientWriteCache { get; set; }

        [DataMember(Name = "pwrites")]
        public List<WriteRecord<Project>> ProjectWriteCache { get; set; }

        [DataMember(Name = "twrites")]
        public List<WriteRecord<Tag>> TagWriteCache { get; set; }

        [OnDeserializing]
        public void OnDeserializing(StreamingContext context)
        {
            this.SetDefaults();
        }

        private void SetDefaults()
        {
            this.Tags = new Dictionary<ulong, CacheRecord<Tag>>();
            this.Clients = new Dictionary<ulong, CacheRecord<Client>>();
            this.TimeEntries = new Dictionary<ulong, CacheRecord<TimeEntry>>();
            this.Projects = new Dictionary<ulong, CacheRecord<Project>>();
            this.Workspaces = new Dictionary<ulong, CacheRecord<Workspace>>();

            this.TimeEntryWriteCache = new List<WriteRecord<TimeEntry>>();
            this.ProjectWriteCache = new List<WriteRecord<Project>>();
            this.TagWriteCache = new List<WriteRecord<Tag>>();
            this.ClientWriteCache = new List<WriteRecord<Client>>();
            this.WorkspaceWriteCache = new List<WriteRecord<Workspace>>();
        }
    }

    [DataContract]
    public class WriteRecord<T>
    {
        public WriteRecord(T entity, WriteType type)
        {
            this.Entity = entity;
            this.Type = type;
        }

        [DataMember(Name = "entity")]
        public T Entity { get; private set; }

        [DataMember(Name = "type")]
        public WriteType Type { get; set; }
    }

    [DataContract(Name = "wtype")]
    public enum WriteType
    {
        [EnumMember]
        Create,

        [EnumMember]
        Update,

        [EnumMember]
        Delete
    }

    [DataContract]
    public sealed class CacheRecord<T>
        where T : class, IEntity
    {
        private T entity;

        public CacheRecord()
        {
            this.LastTouch = DateTime.Now;
        }

        public CacheRecord(T entity) : this()
        {
            this.Entity = entity;
        }

        [DataMember(Name = "entity")]
        public T Entity
        {
            get
            {
                return this.entity;
            }

            set
            {
                this.entity = value;
                this.LastTouch = DateTime.Now;
            }
        }

        [DataMember(Name = "ts")]
        public DateTime LastTouch { get; private set; }

        public bool IsOlderThanMinutes(int minutes)
        {
            if (!Toggly.HasInternetAccess())
            {
                return false;
            }

            return this.LastTouch < DateTime.Now.AddMinutes(-Math.Abs(minutes));
        }
    }
}
